﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.Reflection;
using System.Xaml;
using System.Activities.XamlIntegration;
using Microhard.Core.DBUtility;
using System.Configuration;
using System.Activities.DurableInstancing;
using Microhard.ApproveFlow.Buz.DataAccess;
using System.IO;
using Microhard.Core;
using Microhard.ApproveFlow.Buz.Msg;

namespace Microhard.ApproveFlow.Buz.Utility
{
    public class FlowHelper
    {
        /// <summary>
        /// 从数据库获得workflow xaml
        /// http://www.cnblogs.com/zhuqil/archive/2010/03/09/loading-xaml-workflows-in-wf4.html
        /// </summary>
        /// <returns></returns>
        public static Activity LoadActivityFromFile(Guid flowchartID)
        {
            Activity rtn = null;
            MicroHardApproveFlowEntities db = new MicroHardApproveFlowEntities();
            var chartXAML = db.t_FlowChart.SingleOrDefault(s => s.FlowChartId == flowchartID);
            //加载xaml文件所需的app domain
            using (Stream stream = new MemoryStream(chartXAML.Content))
            {
                //var asm = Assembly.LoadFile(@"G:\CTYWX\Microhard.ApproveFlow\Microhard.CustomActivities\bin\Debug\Microhard.CustomActivities.dll");
                //var settings = new XamlXmlReaderSettings() { LocalAssembly =  };
                var reader = new XamlXmlReader(stream);
                var act = ActivityXamlServices.Load(reader);
                rtn = act;
                //if (act != null)
                //{
                //    rtn = act as DynamicActivity;
                //}
            }
            return rtn;
        }

        public static SqlWorkflowInstanceStore GetStore()
        {
            //装载sql cnn string
            string cnn = ConfigurationManager.ConnectionStrings["MicroHardApproveFlowConnectionString"].ConnectionString;
            SqlWorkflowInstanceStore ins = new SqlWorkflowInstanceStore(cnn);

            //当工作流执行完毕后，从数据库中删除流程实例。默认为DeleteAll.
            ins.InstanceCompletionAction = InstanceCompletionAction.DeleteAll;

            //声明，在wf实例上，需要存储附加信息（业务数据）
            //var dataNameSpace = XNamespace.Get("http://xhinker.com/");
            //List<XName> varProperties = new List<XName>();
            //varProperties.Add(dataNameSpace.GetName("BusinessSheetXName"));
            //ins.Promote("additionalPty", varProperties, null);

            //如果在多个host wf的环境里面，我们使用下面的代码，表示
            //每次加载同一个wf实例
            //InstanceHandle handle = ins.CreateInstanceHandle();
            //InstanceView view = ins.Execute(handle, new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(5));
            //handle.Free();
            //ins.DefaultInstanceOwner = view.InstanceOwner;

            return ins;
        }

        public static ExecutedResult StartWorkflow(string flowchart, Guid buzDataID)
        {
            MicroHardApproveFlowEntities db = new MicroHardApproveFlowEntities();
            ExecutedResult rtn = new ExecutedResult();
            //获得workflow xaml文件内容
            //根据flowKeyName 获得流程图
            var fl = db.t_FlowChart.SingleOrDefault(s => s.FlowChartName == flowchart);
            Activity flow = LoadActivityFromFile(fl.FlowChartId);

            //采取流程ID与业务ID在数据库中建立关联的方式，所以不需要传递参数
            //构造流程的InArgument
            //IDictionary<string, object> parms = new Dictionary<string, object>();
            //parms.Add("BusinessSheetID", busID);
            //parms.Add("OperatorID", userID);
            //parms.Add("OperatorName", userName);

            //流程开始，传入申请人的相关信息 
            WorkflowApplication wfApp = new WorkflowApplication(flow);
            wfApp.InstanceStore = GetStore();
            //指定为unload,代表需要固化workflow并从内存中unload
            //指定为persist,会被workflow的实例锁定，退出并不是以unload方式,通常再次获取、
            //实例的时候，会出现错误“此流程被一个实例锁定，无法提取”
            wfApp.PersistableIdle = (e) =>
            {
                return PersistableIdleAction.Unload;
            };
            try
            {
                //启动流程
                wfApp.Run();
                rtn.WorkflowInstanceID = wfApp.Id;
                //保存流程与业务数据之间的关系
                var data = db.t_WorkflowDyncStatus.SingleOrDefault(s => s.BuzID == buzDataID);
                data.InstanceID = wfApp.Id;
                db.SaveChanges();
            }
            catch (Exception ex)
            {
                rtn.ErrorMsg.Add("StartWorkfow", ex.Message);
            }
            return rtn;
        }

        public static ExecutedResult ApproveWorkflow(Guid flowChartid, Guid WorkflowInstanceID, Guid buzDataID, Guid userID, string userName, string bookmarkName)
        {
            ExecutedResult rtn = new ExecutedResult();
            var flow = LoadActivityFromFile(flowChartid);

            //装载流程
            WorkflowApplication wfApp = new WorkflowApplication(flow);
            wfApp.InstanceStore = GetStore();
            try
            {
                //装载流程
                wfApp.Load(WorkflowInstanceID);
                //传递审批结果
                Dictionary<string, object> parms = new Dictionary<string, object>();
                parms.Add("BusinessSheetID", buzDataID);
                parms.Add("OperatorID", userID);
                parms.Add("OperatorName", userName);

                wfApp.ResumeBookmark(bookmarkName, parms);
                //卸载流程
                wfApp.Unload();
            }
            catch (Exception ex)
            {
                rtn.ErrorMsg.Add("ApproveWorkflow", ex.Message);
            }
            return rtn;
        }

        public static ExecutedResult SaveXAMLInDB(string path, Guid flowChartid)
        {
            ExecutedResult rtn = new ExecutedResult();
            var bytes = System.IO.File.ReadAllBytes(path);
            MicroHardApproveFlowEntities db = new MicroHardApproveFlowEntities();
            var sm = db.t_FlowChart.SingleOrDefault(s => s.FlowChartId == flowChartid);
            if (sm != null)
            {
                sm.Content = bytes;
                sm.WFXAMLFileName = path;
            }
            try
            {
                db.SaveChanges();
            }
            catch (Exception ex)
            {
                Log.Error("SaveXAMLInDB", ex);
                rtn.ErrorMsg.Add("SaveXAMLInDB", FlowChartModelMsg.FlowChartAddFailed);
            }
            return rtn;
        }
    }
}
